#include "pwm.h"
#include "avrlibdefs.h"

CPWM::CPWM(u08 devNum, u08 prescale, u16 period, u08 dutyCycle,
		ePORT portNumber, u08 pinNumber, bool pullup, eChannel channel) :
	CCounter(devNum, prescale), Cpin(portNumber, pinNumber, ePinOut, pullup) {
	this->period = period;
	this->duty = dutyCycle;
	this->channel = channel;
	cbi(_MMIO_BYTE(this->timskn), OCIE1B);
	if (devNum == 1) {
		ICR1 = period;
	}
	cbi(_MMIO_BYTE(this->tccrna), WGM10);
	sbi(_MMIO_BYTE(this->tccrna), WGM11);
	sbi(_MMIO_BYTE(this->tccrnb), WGM12);
	sbi(_MMIO_BYTE(this->tccrnb), WGM13);
	setPolarity( NON_INVERTING);
	setDutyCycle(dutyCycle);
}

void CPWM::setPolarity(ePolarity pol) {

	if (pol == NON_INVERTING) {
		switch (channel) {
		case OCR_A:
			sbi(_MMIO_BYTE(this->tccrna), COM1A1);
			cbi(_MMIO_BYTE(this->tccrna), COM1A0);
			break;
		case OCR_B:
			sbi(_MMIO_BYTE(this->tccrnb), COM1B1);
			cbi(_MMIO_BYTE(this->tccrnb), COM1B0);
			break;
		}
	} else {
		switch (channel) {
		case OCR_A:
			sbi(_MMIO_BYTE(this->tccrna), COM1A1);
			sbi(_MMIO_BYTE(this->tccrna), COM1A0);
			break;
		case OCR_B:
			sbi(_MMIO_BYTE(this->tccrnb), COM1B1);
			sbi(_MMIO_BYTE(this->tccrnb), COM1B0);
			break;
		}
	}
}

void CPWM::stop(ePinState state) {
	// Set normal port operation
	switch (channel) {
	case OCR_A:
		cbi(_MMIO_BYTE(this->tccrna), COM1A1);
		cbi(_MMIO_BYTE(this->tccrna), COM1A0);
		break;
	case OCR_B:
		cbi(_MMIO_BYTE(this->tccrnb), COM1B1);
		cbi(_MMIO_BYTE(this->tccrnb), COM1B0);
		break;
	}
	if (state == ePinHigh) {
		setHigh();
	} else {
		setLow();
	}
}

void CPWM::start(ePolarity pol) {
	setPolarity(pol);
	CCounter::start();
}

void CPWM::setDutyCycle(u16 dutyCycle) {
	duty = (u16) ((float) dutyCycle / (float) 100.0 * period);
	if (devNum == 1) {
		OCR1A = duty;
	} else {
		_MMIO_BYTE(this->ocrna) = duty;
	}
}
